<!DOCTYPE html>
<html>
<head>
<title>Coupled Disks Motion Diagram</title>
<style>
    body {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        margin: 0;
        background-color: #f0f0f0;
    }
    canvas {
        border: 1px solid #ccc;
        background-color: #fff;
    }
</style>
</head>
<body>
<canvas id="physicsCanvas" width="500" height="420"></canvas>
<script>
    const canvas = document.getElementById('physicsCanvas');
    const ctx = canvas.getContext('2d');

    // --- Style and Helper Functions ---
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 2;
    ctx.fillStyle = 'black';

    function drawArrow(ctx, fromx, fromy, tox, toy) {
        const headlen = 10;
        const dx = tox - fromx;
        const dy = toy - fromy;
        const angle = Math.atan2(dy, dx);
        ctx.beginPath();
        ctx.moveTo(fromx, fromy);
        ctx.lineTo(tox, toy);
        ctx.moveTo(tox, toy);
        ctx.lineTo(tox - headlen * Math.cos(angle - Math.PI / 6), toy - headlen * Math.sin(angle - Math.PI / 6));
        ctx.moveTo(tox, toy);
        ctx.lineTo(tox - headlen * Math.cos(angle + Math.PI / 6), toy - headlen * Math.sin(angle + Math.PI / 6));
        ctx.stroke();
    }

    function drawArcArrow(ctx, x, y, radius, startAngle, endAngle, counterClockwise, isLargeArrow) {
        ctx.beginPath();
        ctx.arc(x, y, radius, startAngle, endAngle, counterClockwise);
        ctx.stroke();

        const tipAngle = counterClockwise ? endAngle : startAngle;
        const arrowTipX = x + radius * Math.cos(tipAngle);
        const arrowTipY = y + radius * Math.sin(tipAngle);
        
        // Tangent angle depends on direction
        let tangentAngle;
        if (isLargeArrow) {
             tangentAngle = tipAngle - Math.PI / 2; // For CW motion on top
        } else {
             tangentAngle = tipAngle + Math.PI / 2; // For CCW rotation
        }

        ctx.save();
        ctx.translate(arrowTipX, arrowTipY);
        ctx.rotate(tangentAngle);
        ctx.beginPath();
        ctx.moveTo(0, 0);
        ctx.lineTo(-10, -5);
        ctx.moveTo(0, 0);
        ctx.lineTo(-10, 5);
        ctx.stroke();
        ctx.restore();
    }

    // --- Drawing Parameters ---
    const originX = 60, originY = 360;
    const cx = 280, cy = 200;
    const R = 120;
    const b = 60;
    const theta = Math.PI / 6.5; // Approx 27.7 degrees
    const r = 35;
    const phi = Math.PI / 3; // 60 degrees

    // Derived coordinates for small disk center C'
    const cx_p = cx + b * Math.cos(theta);
    const cy_p = cy - b * Math.sin(theta); // Subtract for canvas's inverted y-axis

    // --- Draw Coordinate System ---
    ctx.font = '20px serif';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    drawArrow(ctx, originX, originY, originX, 40); // Y-axis
    drawArrow(ctx, originX, originY, 450, originY); // X-axis
    ctx.fillText('O', originX - 20, originY + 15);
    ctx.fillText('y', originX + 2, 25);
    ctx.fillText('x', 460, originY);
    ctx.font = 'italic 20px serif'; // Set to italic for physics labels

    // --- Draw Disks and Connections ---
    // Large Disk
    ctx.beginPath();
    ctx.arc(cx, cy, R, 0, 2 * Math.PI);
    ctx.stroke();
    ctx.fillText('C', cx - 15, cy + 15);

    // Small Disk
    ctx.beginPath();
    ctx.arc(cx_p, cy_p, r, 0, 2 * Math.PI);
    ctx.stroke();
    ctx.fillText("C'", cx_p, cy_p - 12);

    // Line segment CC'
    ctx.beginPath();
    ctx.moveTo(cx, cy);
    ctx.lineTo(cx_p, cy_p);
    ctx.stroke();

    // Label 'b'
    ctx.save();
    ctx.translate((cx + cx_p) / 2, (cy + cy_p) / 2);
    ctx.rotate(-theta);
    ctx.fillText('b', 0, -12);
    ctx.restore();

    // --- Draw Angles and Helper Lines ---
    // Dashed lines
    ctx.save();
    ctx.setLineDash([4, 4]);
    // Horizontal line through C
    ctx.beginPath();
    ctx.moveTo(cx - 25, cy);
    ctx.lineTo(cx_p + 15, cy);
    ctx.stroke();
    // Horizontal line through C'
    ctx.beginPath();
    ctx.moveTo(cx_p - r, cy_p);
    ctx.lineTo(cx_p + r + 15, cy_p);
    ctx.stroke();
    ctx.restore();

    // Angle theta
    ctx.beginPath();
    ctx.arc(cx, cy, 30, 0, -theta, true); // CCW arc
    ctx.stroke();
    ctx.fillText('θ', cx + 45, cy - 8);

    // Radius on small disk for angle phi
    ctx.beginPath();
    ctx.moveTo(cx_p, cy_p);
    const px = cx_p + r * Math.cos(phi);
    const py = cy_p - r * Math.sin(phi);
    ctx.lineTo(px, py);
    ctx.stroke();

    // Angle phi
    ctx.beginPath();
    ctx.arc(cx_p, cy_p, 20, 0, -phi, true); // CCW arc
    ctx.stroke();
    ctx.fillText('φ', cx_p + 18, cy_p - 20);

    // --- Draw Motion Arrows ---
    // Arrow on large disk (points left, on top)
    drawArcArrow(ctx, cx, cy, R + 12, -45 * Math.PI / 180, -135 * Math.PI / 180, false, true);

    // Arrow on small disk (counter-clockwise rotation)
    drawArcArrow(ctx, cx_p, cy_p, r * 0.6, -20 * Math.PI / 180, 200 * Math.PI / 180, true, false);

    // --- Draw Figure Caption ---
    ctx.font = '20px serif';
    ctx.fillText('Fig. 2.2.', 250, 400);

</script>
</body>
</html>